import { Button, Col, Form, Input, Layout, Modal, Row, Select, Space } from "antd";
import { useCallback, useEffect, useReducer } from 'react';
import SelectTable from "../../components/SelectTable";
import useDrawer from "../../components/useDrawer";
import alert from "../../utils/alert";
import client from '../../utils/client';
import styles from '../common.module.css';

export default function DatabaseSetting(props) {
  const [form] = Form.useForm();
  const [filter] = Form.useForm();

  const [drawer, drawerHolder] = useDrawer({
    placement: "right",
  });
  const [state, dispatch] = useReducer((state, action) => {
    switch (action.type) {
      case 'providers':
        return { ...state, providers: action.providers };
      case 'loading':
        return { ...state, loading: true };
      case 'loaded':
        return {
          ...state,
          loading: false,
          data: action.data,
          pagination: {
            ...state.pagination,
            total: action.total,
            current: Math.min(Math.floor(action.total / state.pagination.pageSize) + 1, state.pagination.current),
          },
        };
      case 'change':
        return {
          ...state,
          filters: { ...state.filters, ...action.filters },
          pagination: action.pagination || state.pagination,
          sorter: action.sorter || state.sorter,
        };
      case 'exporting':
        return { ...state, exporting: true };
      case 'exported':
        return { ...state, exporting: false };
      default:
        return state;
    }
  }, {
    providers: [],
    loading: true,
    filters: {},
    sorter: {
      field: "名称",
      order: "descend",
    },
    data: [],
    pagination: {
      showTotal: total => `共${total}条`,
      showSizeChanger: true,
      total: 0,
      pageSize: 10,
      current: 1,
    },
    exporting: false,
  });

  useEffect(() => {
    reload();
    // eslint-disable-next-line
  }, [state.filters, state.sorter, state.pagination.current, state.pagination.pageSize]);

  useEffect(() => {
    client.job('GetDbProviders').then(providers => {
      dispatch({ type: 'providers', providers: providers.map(({ code, name }) => ({ value: code, label: name })) });
    });
  }, []);

  const reload = useCallback(function () {
    dispatch({ type: 'loading' });
    // 处理过滤条件
    const filter = [];
    Object.keys(state.filters).forEach(key => {
      if (null == state.filters[key] || '' === state.filters[key]) return;
      filter.push([key, Array.isArray(state.filters[key]) ? 'between' : '=', state.filters[key]]);
    });
    const order = {};
    (Array.isArray(state.sorter) ? state.sorter : [state.sorter]).forEach(s => order[s.field] = s.order);

    client.job('B.DatabaseConnsGet', {
      Filter: filter,
      Order: order,
      PageSize: state.pagination.pageSize,
      PageNo: state.pagination.current,
    }).then(({ Total, Rows }) => {
      dispatch({ type: 'loaded', total: Total, data: Rows });
    });
  }, [state.filters, state.pagination, state.sorter]);

  const save = useCallback(function (handle, record) {
    client.job('DatabaseConnections', {
      Record: record,
    }).then(() => {
      handle.destroy();
      reload();
    });
  }, [reload]);

  const test_connect = useCallback(function () {
    const { 类型, 连接字符串 } = form.getFieldsValue();
    client.job('B.DBConnectTest', {
      Type: 类型,
      ConnectionString: 连接字符串,
    }).then((msg) => msg ? alert('连接失败') : alert('连接成功'));
  }, [form]);

  const edit = useCallback(function (record) {
    // 从连接字符串中解析出各项值
    const values = record && record.连接字符串 ? (() => {
      const params = {};
      record.连接字符串.split(';').forEach(s => {
        const [k, v] = s.split('=');
        params[k] = v;
      });
      return {
        服务器: params['Data Source'] || params['Server'] || params['Host'] || null,
        端口: params['Port'] || null,
        数据库: params['Database'] || null,
        用户名: params['User Id'] || null,
        密码: params['Password'] || null,
      };
    })() : {};
    // 打开抽屉
    record ? form.setFieldsValue({ ...record, ...values }) : form.resetFields();
    const handle = drawer.open({
      title: record ? '修改连接' : '新增连接',
      width: 500,
      content: (
        <Form form={form} labelCol={{ span: 6 }}
          onValuesChange={(changedValues, allValues) => {
            if (changedValues.连接字符串) return;
            // 根据类型构造连接字符串
            let str;
            switch (allValues.类型) {
              case 'SQLITE': {
                str = `Data Source=${allValues.服务器 || ''};Pooling=true;Mode=ReadWrite;`;
                break;
              }
              case 'MYSQL': {
                str = `Data Source=${allValues.服务器 || ''};Port=${allValues.端口 || 3306};Database=${allValues.数据库 || ''};User Id=${allValues.用户名 || ''};Password=${allValues.密码 || ''};Character Set=utf8;Allow User Variables=True;`;
                break;
              }
              case 'ORACLE': {
                str = `Data Source=${allValues.服务器 || ''};User Id=${allValues.用户名 || ''};Password=${allValues.密码 || ''};`;
                break;
              }
              case 'MSSQL': {
                str = `Data Source=${allValues.服务器 || ''},${allValues.端口 || 1433};Database=${allValues.数据库 || ''};User Id=${allValues.用户名 || ''};Password=${allValues.密码 || ''};TrustServerCertificate=True;`;
                break;
              }
              case 'PGSQL': {
                str = `Server=${allValues.服务器 || ''};Port=${allValues.端口 || 5432};Database=${allValues.数据库 || ''};User Id=${allValues.用户名 || ''};Password=${allValues.密码 || ''};`;
                break;
              }
              case 'DM': {
                str = `Data Source=${allValues.服务器 || ''};User Id=${allValues.用户名 || ''};Password=${allValues.密码 || ''};`;
                break;
              }
              default: {
                break;
              }
            }
            form.setFieldsValue({ 连接字符串: str });
          }}>
          <Form.Item name="名称" label="名称" rules={[{ required: true }]}>
            <Input allowClear={true} autoComplete="off" />
          </Form.Item>
          <Form.Item name="类型" label="类型" rules={[{ required: true }]}>
            <Select options={state.providers} />
          </Form.Item>
          <Form.Item name="服务器" label="服务器"><Input allowClear={true} /></Form.Item>
          <Form.Item name="端口" label="端口"><Input allowClear={true} /></Form.Item>
          <Form.Item name="数据库" label="数据库"><Input allowClear={true} /></Form.Item>
          <Form.Item name="用户名" label="用户名"><Input allowClear={true} /></Form.Item>
          <Form.Item name="密码" label="密码"><Input allowClear={true} /></Form.Item>
          <Form.Item name="连接字符串" label="连接字符串" rules={[{ required: true }]}><Input /></Form.Item>
          <Button onClick={test_connect} style={{ width: '25%' }}>测试连接</Button>
        </Form>
      ),
      async onOk() {
        const values = await form.validateFields();
        const target = Object.assign({}, record, values);

        // 如果是MP连接, 需要先检测连接是否正常, 用户表是否存在, 否则需要让用户二次确认
        if (target.名称 === 'MP') {
          const msg = await client.job('B.DBConnectTest', {
            Type: target.类型,
            ConnectionString: target.连接字符串,
            User: true,
          });
          if (msg) {
            Modal.confirm({
              title: '危险操作确认',
              content: "该连接未能通过用户访问测试, 继续保存会导致系统无法登录!",
              onOk() {
                save(handle, target);
              }
            });
            return Promise.reject();
          }
        }
        save(handle, target);
      }
    });
  }, [form, drawer, save, state.providers, test_connect]);

  function remove(record) {
    Modal.confirm({
      title: '删除确认',
      content: "数据删除后不可恢复, 请确定",
      onOk() {
        client.job('DatabaseConnections', {
          Record: record,
          Delete: true,
        }).then(() => reload());
      }
    });
  }

  const export_xls = useCallback(function () {
    dispatch({ type: 'exporting' });
    const filter = [];
    Object.keys(state.filters).forEach(key => {
      if (!state.filters[key]) return;
      filter.push([key, Array.isArray(state.filters[key]) ? 'between' : '=', state.filters[key]]);
    });
    const order = {};
    (Array.isArray(state.sorter) ? state.sorter : [state.sorter]).forEach(s => order[s.field] = s.order);

    client.export_xls('B.CardRExport', {
      Card: '数据库连接',
      Model: ['名称', '类型', '连接字符串'],
      Filter: filter,
      Order: order,
    }).then(() => dispatch({ type: 'exported' }));
  }, [state.filters, state.sorter]);

  const import_xls = useCallback(function () {
    client.import('B.CardWImport', {
      Card: '数据库连接',
      Model: ['名称', '类型', '连接字符串'],
    }).catch(e => alert('导入失败', e.message, { type: 'error' })).then(reload);
  }, [reload]);

  return (
    <Layout>
      <Layout.Header className={styles.toolbar}>
        <Form labelCol={{ span: 4 }} form={filter}
          onFinish={values => dispatch({ type: 'change', filters: values })}>
          <Row gutter={[8, 8]}>
            <Col xs={24} sm={12} md={8} lg={6}>
              <Form.Item label="名称" name="名称">
                <Input allowClear={true} />
              </Form.Item>
            </Col>
            <Col xs={24} sm={12} md={8} lg={6}>
              <Form.Item label="类型" name="类型">
                <Input allowClear={true} />
              </Form.Item>
            </Col>
            <Col span={24}>
              <Space>
                <Button htmlType="submit">查询</Button>
                <Button onClick={() => filter.resetFields()}>重置</Button>
                <Button type="primary" onClick={() => edit()}>新增</Button>
                <Button loading={state.exporting} onClick={import_xls}>导入</Button>
                <Button loading={state.exporting} onClick={export_xls}>导出</Button>
              </Space>
            </Col>
          </Row>
        </Form>
      </Layout.Header>
      <Layout.Content>
        <SelectTable loading={state.loading} dataSource={state.data} pagination={state.pagination}
          onChange={(pagination, filters, sorter) => dispatch({ type: 'change', pagination, filters, sorter })}
          rowSelection={null}
          onRow={(record, index) => ({ onDoubleClick: () => edit(record) })}
          columns={[{
            title: '名称',
            dataIndex: '名称',
            width: 150,
            ellipsis: true,
            sorter: {
              multiple: 1,
            },
          }, {
            title: '类型',
            dataIndex: '类型',
            width: 150,
            ellipsis: true,
            sorter: {
              multiple: 2,
            },
          }, {
            title: '连接字符串',
            dataIndex: '连接字符串',
            ellipsis: true,
          }, {
            title: '操作',
            key: '操作',
            width: 100,
            render(record) {
              return (
                <Space style={{ color: '#00bfff', cursor: 'pointer' }}>
                  <span onClick={() => edit(record)}>编辑</span>
                  <span onClick={() => remove(record)}>删除</span>
                </Space>
              );
            },
          }]} />
      </Layout.Content>
      {drawerHolder}
    </Layout>
  )
}